<?php
/**
 * Users controller.
 * @package    sitrack 
 * @author     Simon Downes <simon@simondownes.co.uk>
 * @copyright  Copyright (c) 2007, Simon Downes 
 * @license    http://www.opensource.org/licenses/mit-license.php
 */

/**
 * This controller provides the methods for performing CRUD operations on users,
 * along with methods for signing in/out and account activation.  
 *
 * @package    sitrack 
 * @author     Simon Downes <simon@simondownes.co.uk>
 * @copyright  Copyright (c) 2007, Simon Downes 
 * @license    http://www.opensource.org/licenses/mit-license.php
 */
class Users_Controller extends SPF_Controller {

   /**
    * Constructor.
    * @return       void
    */
   public function __construct() {
      /* construct the parent object */
      parent::__construct(__CLASS__);
   }

   /**
    * Destructor.
    * @return       void
    */
   public function __destruct() {
      parent::__destruct();
   }

   /**
    * Determines if the client is permitted to access this controller and perform the requested action.
    * Access to this controller requires a signed-in user, unless the requested action is one of:
    * - signin()
    * - signout()
    * - register()
    * - activate()
    *
    * @return  boolean   true if access is allowed, false otherwise.
    */
   public function authenticate() {
   
      switch( SPF::$route['action'] ) {
         case 'signin':
         case 'signout':
         case 'register':
         case 'activate':
         case 'reset_password':
            return true;
         default:
            return (SPF::$session->user != NULL);
      }
      
   } // authenticate
   
   /**
    * Authenticates a username and password and if successful stores an array of user data in the session.
    * 
    * @return  void
    */
   public function signin() {
      
      SPF::$session->user = NULL;;
      
      if( SPF::form_submitted('frm_signin') ) {
         
         $user_name = SPF::post('user_name');
         $password  = SPF::hash(SPF::post('password'));
         
         $user_status = User::signin($user_name, $password);
         
         switch( $user_status ) {
            
            // invalid username/password
            case NULL:
            case 'DELETED':
               $this->assign('invalid', true);
               $this->assign('user_name', $user_name);
               break;
            
            // user has not yet been activated so we should tell them that...
            case 'NOT_ACTIVATED':
               $this->assign('not_activated', true);
               $this->assign('user_name', $user_name);
               break;
               
            case 'ACTIVE':
               $user = new User();
               $user->fetch($user_name);
               SPF::$session->user = $user->to_array();
               SPF::redirect();
               break;
         
         } // switch $user_status
         
      }
      
      $this->assign('allow_registration', SPF::$registry->get('users.allow_registration'));
      
      $this->display('signin');
      
   } // signin
   
   /**
    * Destroys an authenticated user session.
    * 
    * @return  void
    */
   public function signout() {
      
      SPF::$session->destroy();
      
      SPF::redirect('users', 'signin');
      
   } // signout
   
   /**
    * Creates a new user account in the application.
    * If the option 'users.allow_registration' is set in the registry then users are allowed to register themselves,
    * otherwise users can only be registered by an existing user.<br />
    * Once registered, users will receive an email either allowing them to activate their account
    * (if the 'users.auto_activation' option is set in the registry) or informing them that their account is awaiting 
    * activation by an administrator.
    * 
    * @return  void
    */
   public function register() {
      
      // if registration is disabled and there is no current user then redirect to homepage
      if( !(int) SPF::$registry->get('users.allow_registration') && !SPF::$session->user )
         SPF::redirect();
      
      if( SPF::form_submitted('frm_register') ) {

         // load the request lookup object
         $user = new User();
         
         // don't use from_array() as people could post extra data in the request,
         // and we don't want people activating their accounts and setting groups, etc...
         $user->user_name    = SPF::post('user_name');
         $user->display_name = SPF::post('display_name');
         $user->email        = SPF::post('email');
         $user->password     = SPF::post('new_password');
         $user->confirm_pw   = SPF::post('confirm_pw');
         
         $user->validate();
         
         // check if user already exists
         if( $user->exists(SPF::post('user_name')) ) {
            $user->set_error('user_name', 'User already exists.');
         }
         
         // everything is ok...
         if( !$user->has_errors() ) {
            
            // allow the user to activate their account if either new users are allowed to or an existing user is creating a new user
            $auto_activate = (int) SPF::$registry->get('users.auto_activation') || SPF::$session->user;
            
            // update the user record
            if( $success = $user->update(false) ) {
               SPF::$app->notify('new_user', $user->to_array(), SPF::post('new_password'), $auto_activate);
            }
            
            $this->assign('success', $success);
            $this->assign('auto_activate', $auto_activate);
            
         }

         $this->assign('user', $user->to_array());

      } // is_submitted

      $this->display('register');

   } // register
   
   /**
    * Activates a users account.
    * Once activated, users will receive an email inviting them to sign in.
    * 
    * @param   string    $user_name   user to activate.
    * @param   string    $password    hash of the users password.
    * @return  void
    */
   public function activate( $user_name = NULL, $password = NULL) {
      
      if( !$user_name || !$password )
         $success = false;
      else
         $success = User::activate($user_name, $password);
      
      $user = new User();
      $user->fetch( $user_name );
      
      // if successful and there is a current user then
      // email the new user to tell them their account is active and then return to the user list
      if( $success && SPF::$session->user ) {
         SPF::$app->notify('activated_user', $user->to_array());
         SPF::redirect('users', 'index');
      }
      
      $this->assign('success', $success);
      $this->assign('user', $user->to_array());
      
      $this->display('activated');
      
   } // activate
   
   /**
    * Allows a user to edit their personal information and change their password.
    * 
    * @return  void
    */
   public function myinfo() {
      
      // fetch the current users data
      $user = new User();
      $user->fetch(SPF::$session->user['user_name']);
      
      if( SPF::form_submitted('frm_my_info') ) {

         // don't use from_array() as people could post extra data in the request,
         // and we don't want people activating their accounts and setting groups, etc...
         $user->display_name = SPF::post('display_name');
         $user->email        = SPF::post('email');
         
         if( SPF::post('new_password') ) {
            $user->password     = SPF::post('new_password');
            $user->confirm_pw   = SPF::post('confirm_pw');
         }
         
         $user->validate();
         
         // everything is ok...
         if( !$user->has_errors() ) {
               
            // update the user record
            $user->update(false);
            
            SPF::flash(SiTrack::MSG_SAVED, 'success');
            
            // redirect to dashboard
            SPF::redirect();
            
         }

         SPF::flash(SiTrack::MSG_ERRORS, 'error');
         
      } // is_submitted

      $this->assign('user', $user->to_array());

      $this->display('my_info');

   } // myinfo
   
   /**
    * Allows a user to edit their personal information and change their password.
    * 
    * @return  void
    */
   public function reset_password( $user_name = NULL, $password = NULL ) {
      
      // if neither username or password is specified then display prompt for username
      if( ($user_name === NULL) && ($password === NULL) ) {
         d('user');
         $this->assign('prompt', 'user');
         
         if( SPF::form_submitted('frm_reset') ) {
   
            // fetch the users data
            $user = new User();
            $user->fetch(SPF::post('user_name'));
            
            if( !$user->user_name ) {
               d('invalid user');
            }
            else {
               d('send email');
            }
            
         } // is_submitted

      }
      // can only reset passwords when valid credentials are supplied and user is active
      elseif( User::sign_in($user_name, $password) == 'ACTIVE' ) {
         
         d('password');
         
         $this->assign('prompt', 'password');
         
         // fetch the users data
         $user = new User();
         $user->fetch($user_name);
         
         if( SPF::form_submitted('frm_password') ) {
   
            $user->password   = SPF::post('new_password');
            $user->confirm_pw = SPF::post('confirm_pw');
            
            $user->validate();
            
            // everything is ok...
            if( !$user->has_errors() ) {
                  
               // update the user record
               $user->update(false);
               
               SPF::flash("Password successfully reset", 'success');
               
               // redirect to sign in
               SPF::redirect();
               
            }
   
            SPF::flash(SiTrack::MSG_ERRORS, 'error');
            
         } // is_submitted

      }
      else {
         SPF::redirect('users', 'signin');
      }
      
      $this->display('reset_password');

   } // reset_password
   
   /**
    * Lists the users.
    * 
    * @return  void
    */
   public function index() {
      
      $this->assign('users', User::browse_data());
      
      $this->display('browse');
      
   } // index
   
   /**
    * Allows the user to edit another users information.
    * Changing the other users password or status is not permitted.    
    * 
    * @param   string    $user_name   user to edit.
    * @return  void
    */
   public function edit( $user_name = NULL ) {
      
      // fetch the users data
      $user = new User();
      if( !$user->fetch($user_name) )
         throw new SPF_Exception('User Not Found: '. $user_name);
      
      if( SPF::form_submitted('frm_user') ) {

         // don't use from_array() as people could post extra data in the request,
         // and we don't want people activating their accounts and setting groups, etc...
         $user->display_name = SPF::post('display_name');
         $user->email        = SPF::post('email');
         
         $user->validate();
         
         // everything is ok...
         if( !$user->has_errors() ) {
               
            // update the user record
            $user->update(false);
            
            SPF::flash(SiTrack::MSG_SAVED, 'success');
            
            // redirect to dashboard
            SPF::redirect('users', 'index');
            
         }

         SPF::flash(SiTrack::MSG_ERRORS, 'error');
         
      } // is_submitted

      $this->assign('user', $user->to_array());

      $this->display('edit');

   } // edit
   
   /**
    * Deletes a users account.
    * User records should not actually be deleted from the database as there maybe dependant records
    * in other tables (eg. tickets and comments), therefore the user's personal information should be removed
    * and the status set to deleted.
    * 
    * @param   string    $user_name   user to delete.
    * @return  void
    */
   public function delete( $user_name ) {
      
      if( $user_name ) {
         
         if( $user_name == SPF::$session->user['user_name'] )
            SPF::flash('Cannot delete yourself.', 'error');
            
         // TODO: if user has comments and tickets created/assigned then mark them as disabled
         // otherwise delete the user completely.
         else {
            $user = new User();
            $user->delete($user_name);
            SPF::flash(SiTrack::MSG_DELETED, 'success');
         }
         
      } // if $user_name
      
      SPF::redirect('users');
      
   } // delete
   
} // Users_Controller

?>
